﻿/*
 * Twipler - Twitter Web Client with features.
 *  
 *  Copyright (C) 2009, 2010. Ian Quigley
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details. 
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 */

using System;
using Dimebrain.TweetSharp;
using Dimebrain.TweetSharp.Extensions;
using Dimebrain.TweetSharp.Fluent;
using Dimebrain.TweetSharp.Model;
using Dimebrain.TweetSharp.Model.Twitter;
using Twipler.App;
using Twipler.App.Session;
using Twipler.Xtensions;
using Twipler.App.DataDoc;
using System.Web;

namespace Twipler.Twitter
{
    public class Caller 
    {
        public string UserAuthenticateUrl()
        {
            object[] dbg = Current.Log.EnterMethod("Twitter.RealCaller:UserAuthenticateUrl");

            string authorizeUrl = string.Empty;

            try
            {
                TwitterResult result = FluentTwitter.CreateRequest()
                    .Authentication
                    .GetRequestToken(App.Config.ConsumerKey, App.Config.ConsumerSecret)
                    .Request();

                OAuthToken token = null;
                
                if (result.IsTwitterError)
                    Current.Log.Error(result.AsError().ErrorMessage);
                else
                    token = result.AsToken();
                
                if (token != null)
                    authorizeUrl = FluentTwitter.CreateRequest()
                        .Authentication
                        .GetAuthorizationUrl(token.Token);
            }
            catch (Exception ex)
            {
                Current.Log.Error("Twitter.RealCaller:UserAuthenticateUrl", ex);
            }
            
            Current.Log.ExitMethod(dbg);
            return authorizeUrl;
        }

        public void AuthenticateResponse(string requestToken)
        {
            object[] dbg = Current.Log.EnterMethod("Twitter.RealCaller:AuthenticateResponse");

            var result = FluentTwitter.CreateRequest()
                .Authentication
                .GetAccessToken(Config.ConsumerKey,Config.ConsumerSecret,requestToken)
                .Request().AsToken();

            if (result == null)
                throw new Exception("Failed to retrieve token for user.");

        	Current.SessionTrack.OAuthToken = result;
			
            Current.Log.ExitMethod(dbg);
        }

        private static IFluentTwitter CreateRequest(IInnerSession innerSession)
        {
			OAuthToken userAuthToken = innerSession.OAuthToken;
            if (userAuthToken != null)
                return FluentTwitter.CreateRequest().AuthenticateWith(Config.ConsumerKey, Config.ConsumerSecret, userAuthToken.Token, userAuthToken.TokenSecret);

			string[] credentials = innerSession.Credentials;
            if (credentials != null)
            {
                return FluentTwitter.CreateRequest(
                    new TwitterClientInfo() { ClientName = "Twipler", ClientUrl = "www.twipler.com", ClientVersion = "1" }
                    ).AuthenticateAs(credentials[0], credentials[1]);                
                
            }
            return null;
        }

        public IDataDoc Request(Func<IFluentTwitter, ITwitterLeafNodeJson> twitterCall, bool useGZip)
        {
            object[] dbg = Current.Log.EnterMethod("Twitter.Request " + twitterCall.Method.Name);

            IFluentTwitter ifluentTwitter = CreateRequest(Current.SessionTrack);
            if (ifluentTwitter == null)
                return new DataDocList(DataDocStatus.TwiplerError, "Could not create a request.");

            if (useGZip)
                ifluentTwitter = ifluentTwitter.Configuration.UseGzipCompression();

            IDataDoc doc;
            try
            {
                TwitterResult result = twitterCall(ifluentTwitter).AsJson().Request();
                Current.Log.InfoFormat("Twitter.Request Response code {0} for Uri {1}", result.ResponseHttpStatusCode, result.RequestUri);

                doc = CreateDataDocResult(result);

                Current.Log.DebugFormat("Twitter.Request Response msg : " + result.Response);
            }
            catch (Exception ex)
            {
                Twipler.WebApp.ExceptionReport.Report(ex);
                return new DataDocList(DataDocStatus.TwitterError, ex.Message);
            }
            
            Current.Log.ExitMethod(dbg);

            return doc;
        }

        public string RequestRaw(Func<IFluentTwitter, ITwitterLeafNode> twitterCall, bool useGZip)
        {
            object[] dbg = Current.Log.EnterMethod("Twitter.RequestRaw " + twitterCall.Method.Name);

            IFluentTwitter ifluentTwitter = CreateRequest(Current.SessionTrack);
            if (ifluentTwitter == null)
            {
                Current.Log.ExitMethod(dbg, "Failed to create request.");
                return null;
            }

            if (useGZip)
                ifluentTwitter = ifluentTwitter.Configuration.UseGzipCompression();

            TwitterResult result = twitterCall(ifluentTwitter).Request();

            Current.Log.InfoFormat("Twitter.Request Response code {0} for Uri {1}", result.ResponseHttpStatusCode, result.RequestUri);
            
            Current.Log.ExitMethod(dbg);
            return result.Response;
        }
        
		public void RequestRawAsync(Func<IFluentTwitter, ITwitterLeafNode> twitterCall, TwitterWebCallbackSession callback, IInnerSession innerSession, bool useGZip)
        {
            object[] dbg = Current.Log.EnterMethod("Twitter.RequestRawAsync " + twitterCall.Method.Name);

			IFluentTwitter ifluentTwitter = CreateRequest(innerSession);
            if (ifluentTwitter == null)
            {
				callback(null, null, innerSession);
                Current.Log.ExitMethod(dbg, "Failed to create request.");
                return;
            }

            if (useGZip)
                ifluentTwitter = ifluentTwitter.Configuration.UseGzipCompression();

            Current.Log.ExitMethod(dbg, "Perform ASYNC request.");
 			twitterCall(ifluentTwitter).CallbackTo((object sender, TwitterResult result) => callback(sender, result, innerSession)).RequestAsync();
        }

        private IDataDoc CreateDataDocResult(TwitterResult result)
        {
            IDataDoc doc = new DataDocJson(() => result.Response);

            if ((result.ResponseHttpStatusCode <= 400) || (doc.Find("/error") == null))
                return doc;
            
            return new DataDocList(DataDocStatus.TwitterError, (string)doc.Find("/error").Value);
        }
   }
}